#include <string>

using namespace std;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//****************************************************** ClassSpecial struct**************************************************************
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ClassSpecial
{
        int minLevel;
        string name;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//****************************************************** RaceTemplate struct*******************************************************************
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct RaceTemplate
{
        RaceTemplate()
        {
                name = "Half-Orc";
                strBonus = 2;
                dexBonus = conBonus = wisBonus = 0;
                intBonus = chaBonus = -2;
                speed = 30;
        }
        string name;
        int strBonus, dexBonus, conBonus, intBonus, wisBonus, chaBonus, speed;
        /*
                        STILL TO IMPLEMENT:
        int hitDice, natArmor, baseAge, baseHeight, baseWeight;
        int varAge, varHeight, varWeight, levelModifier;
        char size;
        char** abilities, languages, alignment, deity, eyes, hair, skin;
        */
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//****************************************************** ClassTemplate struct*******************************************************************
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ClassTemplate
{
        ClassTemplate()
        {
                name = "Barbarian";
                hitDice = 12;   
                int BARBARIANBASEFORT[20]               =       {2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12};
                int BARBARIANBASEREFLEX[20]             =       {0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
                int BARBARIANBASEWILL[20]               =       {0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
                int BARBARIANBASEATKBONUS[20]   =       {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
                for (int i = 0; i < 20; ++i)
                {
                        baseFort[i] = BARBARIANBASEFORT[i];
                        baseReflex[i] = BARBARIANBASEREFLEX[i];
                        baseWill[i] = BARBARIANBASEWILL[i];
                        baseAtkBonus[i] = BARBARIANBASEATKBONUS[i];
                }
        }
        string name;
        int hitDice;
        int baseFort[20], baseReflex[20], baseWill[20], baseAtkBonus[20];       //these arrays will store base saves from levels 1-20, so baseFort[4] 
                                                                                                                                                //would refer to the base saving throw of the character at level 5
        /*
                        STILL TO IMPLEMENT:
        ClassSpecial* specials;
        char** alignment, deity, weapons;
        */

};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//****************************************************** Character class*******************************************************************
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Character
{
public:
        const bool isvalid() { return valid; }

        int getStr() { return baseStr + strBonus; }
        int getCon() { return baseCon + conBonus; }
        int getDex() { return baseDex + dexBonus; }
        int getInt() { return baseInt + intBonus; }
        int getWis() { return baseWis + wisBonus; }
        int getCha() { return baseCha + chaBonus; }

        int getStrMod() { return calcStatMod(getStr()); }
        int getConMod() { return calcStatMod(getCon()); }
        int getDexMod() { return calcStatMod(getDex()); }
        int getIntMod() { return calcStatMod(getInt()); }
        int getWisMod() { return calcStatMod(getWis()); }
        int getChaMod() { return calcStatMod(getCha()); }

        const char* getState() { return state.c_str(); }
        const char* getName() { return name.c_str(); }
        const char* getRace() { return baseRace->name.c_str(); }
        const char* getClass() { return baseClass->name.c_str(); }
        const int getSpeed() { return speed; }
        const int getXP() { return XP; }
        const int getLevel() { return level; }
        const int getCurHP() { return curHP; }
        const int getMaxHP() { return maxHP; }
        const int getAC() { return AC; }
        const int getInit() { return initiative; }
        const int getFortSave() { return baseClass->baseFort[level-1]; }
        const int getWillSave() { return baseClass->baseWill[level-1]; }
        const int getReflexSave() { return baseClass->baseReflex[level-1]; }
		const int getBaseAtkBonus() { return baseClass->baseAtkBonus[level-1]; }

        void adjustXP(int XPToAdd);
        void adjustHP(int HPToAdd);
private:
        friend class CharCreator;
        Character(); // set all values to default values. **NOTE** only CharCreator class should be creating characters!
        bool valid;             // this should always be true, unless there is was some serious issue when the character was instantiated
        string state;   // if invalid, this string can be checked to find out why
        ClassTemplate* baseClass;
        RaceTemplate* baseRace;
        string name;
        int XP, level, curHP, maxHP, AC, speed, initiative;
        int baseStr, baseDex, baseCon, baseInt, baseWis, baseCha;
        int strBonus, dexBonus, conBonus, intBonus, wisBonus, chaBonus;

        //functions
        int calcStatMod(const int& attribute) { return (attribute / 2) -5; }; //the modifier for the stat
        void updateLevel();
        void Leveler(int inputLevel);
        /*
                        To Implement Later:
        char size, gender;
        int age, heightFeet, heightInches, weight, touchAC, flattFootAC;
        string alignment, deity, eyes, hair, skin;
        
        lists:
        feats
        abilities
        languages
        spells
        gear
        inventory

        */

};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//****************************************************** CharCreator class*******************************************************************
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CharCreator
{
public:
        CharCreator();
        char* changeStr(bool add1) { return changeAttribute(curStr, add1); }
        char* changeDex(bool add1) { return changeAttribute(curDex, add1); }
        char* changeCon(bool add1) { return changeAttribute(curCon, add1); }
        char* changeInt(bool add1) { return changeAttribute(curInt, add1); }
        char* changeWis(bool add1) { return changeAttribute(curWis, add1); }
        char* changeCha(bool add1) { return changeAttribute(curCha, add1); }

        int getStr()                    { return curStr; }
        int getDex()                    { return curDex; }
        int getCon()                    { return curCon; }
        int getInt()                    { return curInt; }
        int getWis()                    { return curWis; }
        int getCha()                    { return curCha; }
        int getAbilityPoints()  { return abilityPoints; }

        /*IMPORTANT!!!
        after calling the instantiate() function, make sure that you ALWAYS check the character's valid status that was returned. 
        If (!character.isvalid()), print the character's status (character.status),     and have the user enter it again. Trying to run the game 
        with an invalid character will NOT end happily!
        */
        Character* instantiate();
        char* setRace(char* inputRace);
        char* setClass(char* inputClass);
        void setName(char* input) { name = input;} // Will cause problems with memory.
		void autoAssignPoints();
protected:
private:
        string name;
        int curStr, curDex, curCon, curInt, curWis, curCha, abilityPoints;
        RaceTemplate* curRace;
        ClassTemplate* curClass;

        //functions
        char* changeAttribute(int& attribute, bool add1);
        char* statMod(int& attribute,int amount, int cost);

};

